package org.dei.test.llqruntime;

import org.dei.perla.parser.expressions.*;
import org.dei.perla.sys.device.fpc.*;
import org.dei.perla.sys.llqruntime.*;
import org.dei.perla.sys.llqruntime.datastructures.*;
import org.dei.perla.utils.pipe.*;
import org.dei.perla.utils.waiter.*;

/**
 * Classe che si occupa del retrieving dei dati dal sistema pervasivo
 * @author (dopo tante fatiche) Camplani, Fortunato, Marelli, Rota, Viganò et al.
 *
 */
public class DataCollectorV2 extends Thread{
		
	
	private Waiter<Pipe<Record>> pRecordWaiter;
	private LLQInformations pLLQInfo;
	private Buffer pBuffer;

	
	/**
	 * Costruisce un nuovo oggetto del tipo DataCollector
	 * @param parLLQInfo le informazione su come eseguire la LLQ (??)
	 * @param parInPipe La pipe che collega DC a FPC
	 */
	public DataCollectorV2(Pipe<Record> parInPipe, LLQInformations parLLQInfo, Buffer parBuffer) {
		
		//TODO parBuffer andrebbe incorporato in LLQInformations: in fondo è una info...
		//TODO A mio avviso DataCollector deve ricevere dal Registry un ref all'FPC su cui 
		//     chiedere la parInPipe
		
		pRecordWaiter = new Waiter<Pipe<Record>>();
		pRecordWaiter.start();
		pRecordWaiter.addWaitable(parInPipe.getWaitable());
		
		this.pLLQInfo = parLLQInfo;
		this.pBuffer = parBuffer;
	}
	
	/**
	 * Mette in esecuzione il DataCollector
	 */
	public void run() { 
		
		Record tRecord;
		System.out.println("*** DATA COLLECTOR starts ***");
		Waitable<Pipe<Record>> tTmpWaitable;
		Pipe<Record> tTmpPipe;
		
		do {
			tTmpWaitable = pRecordWaiter.waitNext();
			tTmpPipe = tTmpWaitable.getParentComponent();
			tRecord = tTmpPipe.dequeue();
			
			if(tRecord == null) {
				System.out.println("PIPE CHIUSA");
				tTmpPipe.stop();
				pRecordWaiter.stop();
				tRecord = null;
				break;
			}
			
			System.out.println("Record letto!");
			
			if (performWhere(tRecord))
			{
				//...i record che si "salvano" dopo la performWhere() vengono inseriti nell'LocBuf
				
				pBuffer.addRecord(tRecord);
				System.out.println("Record aggiunto!");
				System.out.println("["+pBuffer.getBuffer().size()+"]"+"<---Il record ora nel buffer contiene il valore: \n" + tRecord);
			}	
			else
			{
				System.out.println("*** Record SCARTATO dalla WHERE***");
			}

			if (pLLQInfo.getFrequenciesTable()!=null) {
				
				if (setFrequencyValue(pLLQInfo.getFrequenciesTable(),tRecord)) {
					System.out.println("*** Frequenza AGGIORNATA ***");
				} else {
					System.out.println("*** FPC ha segnalato errore nella frequenza ***");
				}
				
				//TODO nel caso di errore bisogna vedere se siamo in DO_NOT_SAMPLE... perchè DC in questo
				//	   caso avrebbe finito il suo lavoro.	
			
			}
			
			
		} while (true);
		
		System.out.println("*** DATA COLLECTOR ha terminato ***");
		
		
	}
	
	/**
	 * Metodo helper: data una tabella e un record aggiorna la frequenza di campionamento sull'FPC
	 * @param parTable la tabella
	 * @param parRecord il record
	 * @return TRUE se ok, FALSE altrimenti
	 */
	private boolean setFrequencyValue(SamplingFrequenciesTable parTable, Record parRecord) {
		
		boolean bValue = true;
		
		for (FrequencyRecord tFreqRec : parTable.getTableContent()) {
			
			if (ExpressionEvaluator.evaluate(parRecord,tFreqRec.getFirstOperand())) {
				
				bValue = pLLQInfo.getLinkedFPC().setSamplingTime((long)tFreqRec.getFrequency().getValue()*1000, parTable.getBehaviour());
				if (bValue == true) break;
			}
			
		}
		return bValue;
	}
	/**
	 * Metodo helper per la valutazione della clausola Where
	 * @param parRecord il record su cui controllare la clausola WHERE
	 * @return TRUE se il record è accettabile, FALSE se va' scartato
	 */
	private boolean performWhere(Record parRecord) {
		
		return ExpressionEvaluator.evaluate(parRecord,pLLQInfo.getWhereNode());
	}
}